package xyz.scootaloo.mono.data.entity.auth

import org.ktorm.database.Database
import org.ktorm.dsl.eq
import org.ktorm.dsl.limit
import org.ktorm.dsl.map
import org.ktorm.entity.Entity
import org.ktorm.entity.sequenceOf
import org.ktorm.global.*
import org.ktorm.schema.Table
import org.ktorm.schema.datetime
import org.ktorm.schema.int
import org.ktorm.schema.varchar
import java.time.LocalDateTime

/**
 * 权限用户表对应的实体类
 *
 * DAO [AuthUsers]
 *
 * @author flutterdash@qq.com
 * @since 2021/7/25 14:03
 */
interface AuthUser : Entity<AuthUser> {

    var uid: Int            // 用户唯一标识
    var username: String    // 用户名
    var password: String    // 用户密码
    var salt: String        // 用于加密密码的盐

    var nickName: String   // 昵称
    var avatar: String     // 头像的路径
    var phone: String      // 手机号
    var email: String      // 邮箱
    var sex: Int           // 性别
    var status: Int        // 可以状态, 1为可用, 其他为异常状态

    var roleCode: Int             // 此用户拥有的角色列表的代码
    var ipAddress: String         // 用户登陆时使用的客户端IP地址
    var lastLogin: LocalDateTime  // 用户上次登陆时的日期
    var created: LocalDateTime    // 创建日期
    var updated: LocalDateTime    // 修改日期

    var desc: String   // 描述

    companion object : Entity.Factory<AuthUser>() {
        const val normal = 1
        const val disable = 2

        fun edit(init: AuthUser.() -> Unit): AuthUser {
            return AuthUser {
                status = normal
                sex = 1
                phone = "unknown"
                avatar = "unknown"
                ipAddress = "unknown"

                created = LocalDateTime.now()
                updated = LocalDateTime.now()
                lastLogin = LocalDateTime.now()

                desc = ""
            }.apply(init)
        }
    }
}

object AuthUsers : Table<AuthUser>("auth_user") {

    private val uid = int("uid").primaryKey().bindTo { it.uid }
    private val username = varchar("username").bindTo { it.username }
    private val password = varchar("password").bindTo { it.password }
    private val salt = varchar("salt").bindTo { it.salt }

    private val nickName = varchar("nickname").bindTo { it.nickName }
    private val avatar = varchar("avatar").bindTo { it.avatar }
    private val phone = varchar("phone").bindTo { it.phone }
    private val email = varchar("email").bindTo { it.email }
    private val sex = int("sex").bindTo { it.sex }

    private val status = int("status").bindTo { it.status }
    private val roleCode = int("role_code").bindTo { it.roleCode }
    private val ipAddress = varchar("ip_address").bindTo { it.ipAddress }
    private val lastLogin = datetime("last_login").bindTo { it.lastLogin }

    private val created = datetime("created").bindTo { it.created }
    private val updated = datetime("updated").bindTo { it.updated }
    private val desc = varchar("desc").bindTo { it.desc }

    fun insert(authUser: AuthUser): Int {
        return addEntity(authUser)
    }

    fun list(offset: Int, limit: Int): List<AuthUser> {
        val query = select().limit(offset, limit)
        return query.map { row -> createEntity(row) }
    }

    fun findByUsername(username: String): AuthUser? {
        return findOne {
            it.username eq username
        }
    }

    fun findByUid(uid: Int): AuthUser? {
        return findOne {
            it.uid eq uid
        }
    }

    fun updateStatus(uid: Int, newStatus: Int): Int {
        return update {
            set(it.status, newStatus)
            where {
                it.uid eq uid
            }
        }
    }

    fun updateRoleCode(uid: Int, newRoleCode: Int): Int {
        return update {
            set(it.roleCode, newRoleCode)
            where {
                it.uid eq uid
            }
        }
    }

    fun deleteByUid(uid: Int): Int {
        return delete {
            it.uid eq uid
        }
    }

    fun updateInfo(user: AuthUser): Int {
        return update {
            set(it.username, user.username)
            set(it.nickName, user.nickName)
            set(it.password, user.password)
            set(it.salt, user.salt)
            set(it.phone, user.phone)
            set(it.email, user.email)
            set(it.desc, user.desc)
            set(it.status, user.status)
            set(it.sex, user.sex)
            where {
                it.uid eq user.uid
            }
        }
    }

    fun updateLastLogin(uid: Int): Int {
        return update {
            set(it.lastLogin, LocalDateTime.now())
            where {
                it.uid eq uid
            }
        }
    }
}

val Database.authUsers get() = this.sequenceOf(AuthUsers)
